#define  _WIN32_WINNT   0x0500

#include "GUISys.h"
#include <process.h>
#include <ddraw.h>
#include <stdio.h>
#include <stdarg.h>
#include "..\game\MTVERIFY.h"
#include "..\ConfigGUI\global.h"


extern guiimport_t g_gui_imp;
extern void SetShooter(char*, date_ptr, TRAINMODEENUM);
extern void SetShooter2(TECHNIQUETYPE, double, unsigned int);
extern void SetTarget(unsigned int);

#define KO_THRDGUI		0
#define KO_EVENTQUIT	1
#define KO_ALL			2
static	HANDLE			g_hKernelObjs[KO_ALL];

static	DWORD				g_dwIdThrd;
#define MAINWNDCLASSNAME	TEXT("PredatorGUI")
#define MAINWNDCAPTION		TEXT("Predator")
static  char				g_szBitmap[] = "..\\Data\\background.bmp";
static	unsigned			WM_USER_QUIT_APP;
static  BOOL				g_bActive = FALSE;  // Is application active?
static  DWORD               g_dwUpdateDelay = 1000;

//-----------------------------------------------------------------------------
// Global data
//-----------------------------------------------------------------------------
LPDIRECTDRAW7               g_pDD = NULL;        // DirectDraw object
LPDIRECTDRAWSURFACE7        g_pDDSPrimary = NULL;// DirectDraw primary surface
LPDIRECTDRAWSURFACE7		g_pDDSBack = NULL;
LPDIRECTDRAWSURFACE7        g_pDDSOne = NULL;    // Offscreen surface 1
LPDIRECTDRAWCLIPPER         g_pClipper = NULL;   // Clipper for primary

LPSTR                       g_pBmpBits;     // pointer to DIB bits
HDC                         g_hMemDC;       // memory DC for rendering text
HFONT                       g_hFont;        // font we render text in
HBITMAP                     g_hBitmap;      // bitmap for holding text
int                         g_iBmpHeight;   // height of DIB
int                         g_iBmpWidth;    // width of DIB
int                         g_iWinPosX;     // X pos of client area of window
int                         g_iWinPosY;     // Y pos of client area of window
int                         g_iWinWidth;    // width of client area of window
int                         g_iWinHeight;   // height of client area of window

#define WIDTHBYTES(i)       ((i+31)/32*4)
#define PALETTE_SIZE        2
#define FULL_STRING         "105 mm Gun Launched Missile System"
#define FULL_STRLEN			36

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

void ReleaseAllObjects(void)
{
    if (g_pDD != NULL)
    {
        if (g_pDDSPrimary != NULL)
        {
            IDirectDrawSurface7_Release(g_pDDSPrimary);
            g_pDDSPrimary = NULL;
        }
		if (g_pDDSBack != NULL)
		{
			IDirectDrawSurface7_Release(g_pDDSBack);
			g_pDDSBack = NULL;
		}
        if (g_pDDSOne != NULL)
        {
            IDirectDrawSurface7_Release(g_pDDSOne);
            g_pDDSOne = NULL;
        }
        IDirectDraw_Release(g_pDD);
        g_pDD = NULL;
    }
	if (g_hMemDC != NULL)
    {
        DeleteDC(g_hMemDC);
        g_hMemDC = NULL;
    }
    if (g_hBitmap != NULL)
    {
        DeleteObject(g_hBitmap);
        g_hBitmap = NULL;
    }
    if (g_hFont != NULL)
    {
        DeleteObject(g_hFont);
        g_hFont = NULL;
    }
}

HRESULT InitFail(HWND hWnd, HRESULT hRet, LPCTSTR szError,...)
{
    char                        szBuff[128];
    va_list                     vl;

    va_start(vl, szError);
    vsprintf(szBuff, szError, vl);
    ReleaseAllObjects();
    MessageBox(hWnd, szBuff, "Error", MB_OK);
    DestroyWindow(hWnd);
    va_end(vl);
    return hRet;
}

BOOL InitDC(void)
{
    HDC                         hdc;
    LPBITMAPINFO                pbmi;
    SIZE                        size;

    g_hFont = CreateFont(24,
                         0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
                         ANSI_CHARSET,
                         OUT_DEFAULT_PRECIS,
                         CLIP_DEFAULT_PRECIS,
                         DEFAULT_QUALITY,
                         VARIABLE_PITCH,
                         "Arial");
    if (g_hFont == NULL)
        return FALSE;

    // Create a memory DC for rendering our text into
    hdc = GetDC(HWND_DESKTOP);
    g_hMemDC = CreateCompatibleDC(hdc);
    ReleaseDC(NULL, hdc);
    if (g_hMemDC == NULL)
    {
        DeleteObject(g_hFont);
        return FALSE;
    }

    // Select font, and get text dimensions
    SelectObject(g_hMemDC, g_hFont);
    GetTextExtentPoint32(g_hMemDC, FULL_STRING, sizeof(FULL_STRING) - 1, &size);
    g_iBmpWidth = size.cx + 2;
    g_iBmpHeight = size.cy + 2;

    // Create a dib section for containing the bits
    pbmi = (LPBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFO) +
                                     PALETTE_SIZE * sizeof(RGBQUAD));
    if (pbmi == NULL)
    {
        DeleteObject(g_hFont);
        DeleteDC(g_hMemDC);
        return FALSE;
    }
    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pbmi->bmiHeader.biWidth = g_iBmpWidth;
    pbmi->bmiHeader.biHeight = -1 * g_iBmpHeight;  // negative height = top-down
    pbmi->bmiHeader.biPlanes = 1;
    pbmi->bmiHeader.biBitCount = 8;  // 8bpp makes it easy to get data

    pbmi->bmiHeader.biCompression = BI_RGB;
    pbmi->bmiHeader.biXPelsPerMeter = 0;
    pbmi->bmiHeader.biYPelsPerMeter = 0;
    pbmi->bmiHeader.biClrUsed = PALETTE_SIZE;
    pbmi->bmiHeader.biClrImportant = PALETTE_SIZE;

    pbmi->bmiHeader.biSizeImage = WIDTHBYTES(g_iBmpWidth * 8) * g_iBmpHeight;

    // Just a plain monochrome palette
    pbmi->bmiColors[0].rgbRed = 0;
    pbmi->bmiColors[0].rgbGreen = 0;
    pbmi->bmiColors[0].rgbBlue = 0;
    pbmi->bmiColors[1].rgbRed = 255;
    pbmi->bmiColors[1].rgbGreen = 255;
    pbmi->bmiColors[1].rgbBlue = 255;

    // Create a DIB section that we can use to read the font bits out of
    g_hBitmap = CreateDIBSection(hdc,
                                 pbmi,
                                 DIB_RGB_COLORS,
                                 (void **) &g_pBmpBits,
                                 NULL,
                                 0);
    LocalFree(pbmi);
    if (g_hBitmap == NULL)
    {
        DeleteObject(g_hFont);
        DeleteDC(g_hMemDC);
        return FALSE;
    }

    // Set up our memory DC with the font and bitmap
    SelectObject(g_hMemDC, g_hBitmap);
    SetBkColor(g_hMemDC, RGB(0, 0, 0));
    SetTextColor(g_hMemDC, RGB(255, 255, 255));
    return TRUE;
}

void DisplayText(int x, int y, LPSTR text,...)
{
    char                        buff[256];
    DDSURFACEDESC2              ddsd;
    HRESULT                     hRet;
    va_list                     vlist;
    int                         height;
    int                         width;
    int                         xoffset;
    int                         yoffset;
    LPSTR                       lpbits;
    LPSTR                       lpsrc;
    int                         bytes_pixel;
    RECT                        rcBitmap;
    RECT                        rcWindow;
    RECT                        rcScreen;
    RECT                        rcFinal;

    if (g_pDD == NULL)
        return;

    // Get message to display
    va_start(vlist, text);
    vsprintf(buff, text, vlist);
    va_end(vlist);

    // Output text to our memory DC (the bits end up in our DIB section)
    PatBlt(g_hMemDC, 0, 0, g_iBmpWidth, g_iBmpHeight, BLACKNESS);
    TextOut(g_hMemDC, 1, 1, buff, lstrlen(buff));

    // Get access to the primary surface
    ZeroMemory(&ddsd, sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
    hRet = IDirectDrawSurface7_Lock(g_pDDSBack, NULL, &ddsd, DDLOCK_WAIT, NULL);
    if (hRet == DD_OK)
    {
        switch (ddsd.ddpfPixelFormat.dwRGBBitCount)
        {
            case 8:
                bytes_pixel = 1;
                break;
            case 16:
                bytes_pixel = 2;
                break;
            case 24:
                bytes_pixel = 3;
                break;
            case 32:
                bytes_pixel = 4;
                break;
        }

        // Clip the font bitmap to both the window and the screen
        width = height = 0;

        rcBitmap.left = g_iWinPosX + x;
        rcBitmap.top = g_iWinPosY + y;
        rcBitmap.right = rcBitmap.left + g_iBmpWidth;
        rcBitmap.bottom = rcBitmap.top + g_iBmpHeight;

        rcWindow.left = g_iWinPosX;
        rcWindow.top = g_iWinPosY;
        rcWindow.right = g_iWinPosX + g_iWinWidth;
        rcWindow.bottom = g_iWinPosY + g_iWinHeight;

        rcScreen.left = rcScreen.top = 0;
        rcScreen.right = GetSystemMetrics(SM_CXSCREEN);
        rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN);

        if (IntersectRect(&rcFinal, &rcBitmap, &rcWindow))
        {
            CopyRect(&rcBitmap, &rcFinal);
            if (IntersectRect(&rcFinal, &rcBitmap, &rcScreen))
            {
                // The bitmap is in the window and on screen
                // Now all we need to do is calculate where
                xoffset = rcFinal.left - g_iWinPosX - x;
                width = rcFinal.right - rcFinal.left;
                yoffset = rcFinal.top - g_iWinPosY - y;
                height = rcFinal.bottom - rcFinal.top;
            }
        }

        // Get pointer to place on screen we want to copy the text to
        lpbits = &(((LPSTR) ddsd.lpSurface)[(g_iWinPosY + y) * ddsd.lPitch +
                                            (g_iWinPosX + x) * bytes_pixel]);

        //---------------------------------------------------------------------
        // Copy the bits.  Fastest implementation would be in assembly of
        // course, but for simplicity we show it in C.
        //
        // We always want red text.   The 8bpp works fastest - we generated
        // a monochrome DIB section, so the bits in the DIB section are either
        // 0 or 1.  0 is black, and 1 is red in the standard 8bpp palettized
        // mode, so we can just copy the values.   For larger bpp, we need
        // to copy the data pixel by pixel and do a conversion.
        //---------------------------------------------------------------------
        if (width > 0)
        {
            int                         i;
            int                         j;

            lpsrc = g_pBmpBits;
            lpsrc += WIDTHBYTES(g_iBmpWidth * 8) * yoffset;
            switch (bytes_pixel)
            {
                    //---------------------------------------------------------
                    // 8bpp 
                    //---------------------------------------------------------
                case 1:
                    for (i = 0; i < height; i++)
                    {
                        memcpy(lpbits, lpsrc + xoffset, width);
                        lpbits += ddsd.lPitch;
                        lpsrc += WIDTHBYTES(g_iBmpWidth * 8);
                    }
                    break;
                    //---------------------------------------------------------
                    // 16bpp
                    //---------------------------------------------------------
                case 2:
                    for (i = 0; i < height; i++)
                    {
                        for (j = xoffset; j < (width + xoffset); j++)
                        {
                            if (lpsrc[j])
                            {
                                ((WORD *) lpbits)[j] = 0x7c00;
                            }
                            else
                            {
                                ((WORD *) lpbits)[j] = 0x0000;
                            }
                        }
                        lpbits += ddsd.lPitch;
                        lpsrc += WIDTHBYTES(g_iBmpWidth * 8);
                    }
                    break;
                    //---------------------------------------------------------
                    // 24bpp
                    //---------------------------------------------------------
                case 3:
                    for (i = 0; i < height; i++)
                    {
                        for (j = xoffset; j < (width + xoffset); j++)
                        {
                            if (lpsrc[j])
                            {
                                lpbits[j * 3] = (char) 0x00;
                                lpbits[j * 3 + 1] = (char) 0x00;
                                lpbits[j * 3 + 2] = (char) 0xff;
                            }
                            else
                            {
                                lpbits[j * 3] = (char) 0x00;
                                lpbits[j * 3 + 1] = (char) 0x00;
                                lpbits[j * 3 + 2] = (char) 0x00;
                            }
                        }
                        lpbits += ddsd.lPitch;
                        lpsrc += WIDTHBYTES(g_iBmpWidth * 8);
                    }
                    break;
                    //---------------------------------------------------------
                    // 32bpp
                    //---------------------------------------------------------
                case 4:
                    for (i = 0; i < height; i++)
                    {
                        for (j = xoffset; j < (width + xoffset); j++)
                        {
                            if (lpsrc[j])
                            {
                                ((DWORD *) lpbits)[j] = 0x00ff0000l;
                            }
                            else
                            {
                                ((DWORD *) lpbits)[j] = 0x00000000l;
                            }
                        }
                        lpbits += ddsd.lPitch;
                        lpsrc += WIDTHBYTES(g_iBmpWidth * 8);
                    }
                    break;
            }
        }
        // Done with the primary surface
        IDirectDrawSurface7_Unlock(g_pDDSBack, NULL);
    }
}

HWND RenderMainWnd(HINSTANCE hInstance, HINSTANCE hPrevInstance,
						 PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = MAINWNDCLASSNAME;
	 static TCHAR szWindowCaption[] = MAINWNDCAPTION;
     HWND         hwnd ;
     WNDCLASS     wndclass ;
	 HRESULT      hRet;
	 DDSURFACEDESC2 ddsd;
	 DWORD		  dwScreenWidth, dwScreenHeight;

     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = NULL ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;

     if (!RegisterClass (&wndclass))
     {
          g_gui_imp.Sys_Error("This program requires Windows NT!") ;
          return NULL ;
     }
     hwnd = CreateWindow (szAppName,                  // window class name
                          szWindowCaption,			  // window caption
                          WS_OVERLAPPEDWINDOW,		  // window style
                          0,
                          0,
                          GetSystemMetrics(SM_CXSCREEN),
                          GetSystemMetrics(SM_CYSCREEN),
                          NULL,                       // parent window handle
                          NULL,                       // window menu handle
                          hInstance,                  // program instance handle
                          NULL) ;                     // creation parameters
     
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;

	 ///////////////////////////////////////////////////////////////////////////
     // Create the main DirectDraw object
     ///////////////////////////////////////////////////////////////////////////
     hRet = DirectDrawCreateEx(NULL, (VOID**)&g_pDD, &IID_IDirectDraw7, NULL);
     if (hRet != DD_OK)
	 {
         InitFail(hwnd, hRet, "DirectDrawCreateEx FAILED");
		 goto _ret;
	 }

     // Get normal mode
     hRet = IDirectDraw_SetCooperativeLevel(g_pDD, hwnd, DDSCL_NORMAL);
     if (hRet != DD_OK)
	 {
         InitFail(hwnd, hRet, "SetCooperativeLevel FAILED");
		 goto _ret;
	 }

	 // Make DC, font & DIB section we need
	 if (!InitDC())
     {
         IDirectDraw_Release(g_pDD);
         DestroyWindow(hwnd);
         return FALSE;
     }

     // Create the primary surface
     ZeroMemory(&ddsd, sizeof(ddsd));
     ddsd.dwSize = sizeof(ddsd);
     ddsd.dwFlags = DDSD_CAPS;
     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
     hRet = IDirectDraw_CreateSurface(g_pDD, &ddsd, &g_pDDSPrimary, NULL);
     if (hRet != DD_OK)
	 {
         InitFail(hwnd, hRet, "CreateSurface FAILED");
		 goto _ret;
	 }

     // Create a clipper for the primary surface
     hRet = IDirectDraw_CreateClipper(g_pDD, 0, &g_pClipper, NULL);
     if (hRet != DD_OK)
	 {
         InitFail(hwnd, hRet, "CreateClipper FAILED");
		 goto _ret;
	 }
     hRet = IDirectDrawClipper_SetHWnd(g_pClipper, 0, hwnd);
     if (hRet != DD_OK)
	 {
		 InitFail(hwnd, hRet, "SetHWnd FAILED");
		 goto _ret;
	 }
     hRet = IDirectDrawSurface7_SetClipper(g_pDDSPrimary, g_pClipper);
     if (hRet != DD_OK)
	 {
         InitFail(hwnd, hRet, "SetClipper FAILED");
		 goto _ret;
	 }

	 // Get the dimensions of the viewport and screen bounds
     dwScreenWidth = GetSystemMetrics(SM_CXSCREEN);
     dwScreenHeight = GetSystemMetrics(SM_CYSCREEN);

	 // Create a backbuffer
	 ddsd.dwFlags        = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
     ddsd.dwWidth        = dwScreenWidth;
     ddsd.dwHeight       = dwScreenHeight;
	 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;

     if( FAILED( hRet = IDirectDraw_CreateSurface( g_pDD, &ddsd, &g_pDDSBack, NULL ) ) )
     {
         InitFail(hwnd, hRet, "Create back surface FAILED");
		 goto _ret;
     }

     // Load our bitmap
     g_pDDSOne = g_gui_imp.Load_Bitmap(g_pDD, g_szBitmap, 0, 0);
     if (g_pDDSOne == NULL)
	 {
         InitFail(hwnd, hRet, "DDLoadBitmap FAILED");
		 goto _ret;
	 }
     
_ret:
     return hwnd ;
}

BOOL RestoreAll(void)
{
    return IDirectDrawSurface7_Restore(g_pDDSPrimary) == DD_OK &&
		IDirectDrawSurface7_Restore(g_pDDSBack) == DD_OK &&
        IDirectDrawSurface7_Restore(g_pDDSOne) == DD_OK &&
        g_gui_imp.ReLoad_Bitmap(g_pDDSOne, g_szBitmap) == DD_OK;

}

void UpdateFrame(HWND hWnd)
{
	static DWORD                lastTickCount = 0;
	static int                  currentFrame = 0;
    DWORD                       thisTickCount;
    RECT                        rcRect = { 0, 0, 0, 0 };
    RECT                        destRect = { 0, 0, 0, 0 };
    HRESULT                     hRet;
	POINT						pt = { 0, 0 };
	static char					strbuf[FULL_STRLEN] = FULL_STRING;
	static char*				pStrbuf = strbuf;

	/* set updating frequency */
    thisTickCount = GetTickCount();
    if ((thisTickCount - lastTickCount) <= g_dwUpdateDelay)
		return;

	/* count frame nums */
	if (currentFrame++ > 59)
        currentFrame = 0;

    // Blit the stuff for the next frame
    rcRect.left = 0;
    rcRect.top = 0;
    rcRect.right = 1024;
    rcRect.bottom = 768;

	GetClientRect(hWnd, &destRect);
	pt.x = pt.y = 0;
	ClientToScreen(hWnd, &pt);
	OffsetRect(&destRect, pt.x, pt.y);

    while (TRUE)
    {
        hRet = IDirectDrawSurface7_Blt(g_pDDSBack, &destRect,
										g_pDDSOne, &rcRect, 0, NULL);

        if (hRet == DD_OK)
            break;
        if (hRet == DDERR_SURFACELOST)
        {
            if (!RestoreAll())
                return;
        }
        if (hRet != DDERR_WASSTILLDRAWING)
            return;
    }

	/* display words upon the back surface */
	DisplayText(300, 80, pStrbuf++);
	if ('\0' == *pStrbuf) pStrbuf = strbuf;

    // Flip the surfaces
    while (TRUE)
    {
        hRet = IDirectDrawSurface7_Blt( g_pDDSPrimary, &destRect,
									g_pDDSBack, &destRect, DDBLT_WAIT,
									NULL );
        if (hRet == DD_OK)
            break;
        if (hRet == DDERR_SURFACELOST)
        {
            hRet = RestoreAll();
            if (hRet != DD_OK)
                break;
        }
        if (hRet != DDERR_WASSTILLDRAWING)
            break;
    }

	/* update current time */
	lastTickCount = thisTickCount;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	 DDBLTFX                     ddbltfx;
	 
	 switch (message)
     {
	 case WM_ACTIVATE:
          // Pause if minimized
          g_bActive = !((BOOL)HIWORD(wParam));
          return 0L;

	 case WM_MOVE:
          g_iWinPosX = (int) (short) LOWORD(lParam);
          g_iWinPosY = (int) (short) HIWORD(lParam);
          break;

     case WM_SIZE:
          g_iWinWidth = (int) (short) LOWORD(lParam);
          g_iWinHeight = (int) (short) HIWORD(lParam);
          break;

	 case WM_ERASEBKGND:
		  // Use the blter to do a color fill to clear the front buffer
		  if (NULL != g_pDDSBack && NULL != g_pDDSPrimary)
		  {
			HDC	hDC = (HDC)wParam;
			RECT rcClient, rcWindow;
			POINT pt;
			int rtn = GetClipBox(hDC, &rcClient);
			
			GetClientRect(hwnd, &rcWindow);
			pt.x = pt.y = 0;
			ClientToScreen(hwnd, &pt);
			OffsetRect(&rcClient, pt.x, pt.y);
			OffsetRect(&rcWindow, pt.x, pt.y);
			
			if (2 * (rcClient.bottom - rcClient.top) >
				rcWindow.bottom - rcWindow.top)
			{
				// Use the blter to do a color fill to clear the back buffer
				ZeroMemory(&ddbltfx, sizeof(ddbltfx));
				ddbltfx.dwSize = sizeof(ddbltfx);
				ddbltfx.dwFillColor = 0;
				IDirectDrawSurface7_Blt(g_pDDSBack, NULL, NULL, NULL,
										DDBLT_COLORFILL | DDBLT_WAIT,
										&ddbltfx);
				IDirectDrawSurface7_Blt(g_pDDSPrimary, &rcWindow,
										g_pDDSBack, &rcWindow,
										DDBLT_WAIT, NULL);
			}
		  }
		  break;

	 case WM_SYSCOMMAND:
		  if (SC_CLOSE == wParam)
		  {
			/* destroy the main frame dialog and prepare to exit MFC */
			Destroy_Dialog();
			SetEvent(g_hKernelObjs[KO_EVENTQUIT]);
			return 0;
		  }
		  break;

	 case WM_CLOSE:
		  DestroyWindow(hwnd);
		  return 0;

	 case WM_DESTROY:
		  ReleaseAllObjects();
		  PostQuitMessage(0);
		  return 0;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

DWORD ChildInit(HWND* phWnd, RECT rect)
{
	Init_Config_GUI(g_gui_imp, SetShooter, SetShooter2, SetTarget);
	*phWnd = Init_Dialog(rect);

	if (NULL == *phWnd)
	{
		fprintf(stderr, "Error when init child dialog.\n");
		return -1;
	}

	return 0;
}

DWORD WINAPI GUIInit(void* datain)
{
	MSG		msg;
	RECT	rect;
	HWND	hWnd, hWndChild = NULL;
	DWORD	status = -1;

	/* not using parameter */
	(void)datain;

	/* register a user defined message to notify a closing event */
	WM_USER_QUIT_APP = RegisterWindowMessage("End threads and exit.");

	hWnd =  RenderMainWnd(g_gui_imp.global_hInstance, NULL, NULL, SW_SHOWNORMAL);
	
	if (NULL == hWnd)
	{
		fprintf(stderr, "Error when render main GUI window.\n");
		return -1;
	}

	/* get client rect */
	GetClientRect(hWnd, &rect);

	/* begin displaying main frame dialog */
	if (-1 == (status = ChildInit(&hWndChild, rect))) return status;

	while (TRUE)
	{
		if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
		{
			if (!GetMessage(&msg, NULL, 0, 0))
				break;
			if (msg.hwnd != NULL && msg.hwnd != hWnd)
			{
				Pre_Trans_Dlg_Msgs(msg.hwnd, &msg);
				DispatchMessage (&msg);
			}
			else if (WM_USER_QUIT_APP == msg.message)
			{
				DestroyWindow(hWnd);
				break;
			}
			else
			{
				TranslateMessage(&msg);
				DispatchMessage (&msg);
			}
		}
		else if (g_bActive)
        {
            UpdateFrame(hWnd);
        }
		Sleep(1);
	}

    return (msg.wParam);
}

pboolean PreGUIInit(void)
{
	DWORD result;

	MTVERIFY(g_hKernelObjs[KO_THRDGUI] =
		(HANDLE)_beginthreadex(	
			NULL,		/* security level */ 
			0,			/* stack size */
			GUIInit,	/* starting address of thread procedure */
			NULL,		/* parameter list */
			0,			/* init flag */
			&g_dwIdThrd));	/* thread handle */

	g_hKernelObjs[KO_EVENTQUIT] =
		CreateEvent(NULL, FALSE, FALSE, NULL);

	while (TRUE)
	{
		result = WaitForMultipleObjects(KO_ALL, g_hKernelObjs,
										   FALSE, INFINITE);

		switch (result - WAIT_OBJECT_0)
		{
		case KO_THRDGUI:
			MTVERIFY(CloseHandle(g_hKernelObjs[KO_THRDGUI]));
			return true;

		case KO_EVENTQUIT:
			PostThreadMessage(g_dwIdThrd, WM_USER_QUIT_APP, 0, 0);
			return false;

		default:
			break;
		}
	}

	return true;
}

